#============================================
# #知识点
# 什么是元类呢？一切源自于一句话：python中一切皆为对象。让我们先定义一个类，然后逐步分析

class StanfordTeacher(object):
    school='Stanford'

    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say(self):
        print('%s says welcome to the Stanford to learn Python' %self.name)
# 所有的对象都是实例化或者说调用类而得到的（调用类的过程称为类的实例化），比如对象t1是调用类StanfordTeacher得到的

t1=StanfordTeacher('lili',18)
print(type(t1)) #查看对象t1的类是<class '__main__.StanfordTeacher'>
# 如果一切皆为对象，那么类StanfordTeacher本质也是一个对象，既然所有的对象都是调用类得到的，
# 那么StanfordTeacher必然也是调用了一个类得到的，这个类称为元类
print(type(StanfordTeacher)) # 结果为<class 'type'>，证明是调用了type这个元类而产生的StanfordTeacher，即默认的元类为type
#所有class定义的类与内置定义的类的元类都是type!!!!!!!!!!!!!!
#============================================ 
# 上文我们基于python中一切皆为对象的概念分析出：我们用class关键字定义的类本身也是一个对象，
# 负责产生该对象的类称之为元类（元类可以简称为类的类），内置的元类为type
# class关键字在帮我们创建类时，必然帮我们调用了元类StanfordTeacher=type(...)，
# 那调用type时传入的参数是什么呢？必然是类的关键组成部分，一个类有三大组成部分，分别是
# 1、类名class_name='StanfordTeacher'
# 2、基类们class_bases=(object,)
# 3、类的名称空间class_dic，类的名称空间是执行类体代码而得到的
# 4、调用type时会依次传入以上三个参数
#============================================ 
# 一个类没有声明自己的元类，默认他的元类就是type，除了使用内置元类type，
# 我们也可以通过继承type来自定义元类，然后使用metaclass关键字参数为一个类指定元类
class Mymeta(type):        #只有继承了type类才能称之为一个元类，否则就是一个普通的自定义类
        # print(self) #<class '__main__.StanfordTeacher'>
        # print(class_bases) #(<class 'object'>,)
        # print(class_dic) #{'__module__': '__main__', '__qualname__': 'StanfordTeacher', 'school': 'Stanford', '__init__': <function StanfordTeacher.__init__ at 0x102b95ae8>, 'say': <function StanfordTeacher.say at 0x10621c6a8>}
        def __init__(self,class_name,class_bases,class_dic):
            super(Mymeta, self).__init__(class_name, class_bases, class_dic)  # 重用父类的功能
            if class_name.islower():
                raise TypeError('类名%s请修改为驼峰体' %class_name)
            if '__doc__' not in class_dic or len(class_dic['__doc__'].strip(' \n')) == 0:
                raise TypeError('类中必须有文档注释，并且文档注释不能为空')

        def __new__(cls,*arg,**kwargs):
            pass  #必须返回一个对象

# StanfordTeacher=Mymeta('StanfordTeacher',(object),{...})
class StanfordTeacher(object,metaclass=Mymeta): 
    school='Stanford'
    """
    使用自定义元类
    """
    #使用自定义元类
    def __init__(self,name,age):
        #使用自定义元类
        self.name=name
        self.age=age

    def say(self):
        #使用自定义元类
        print('%s says welcome to the Stanford to learn Python' %self.name)
# 调用Mymeta发生三件事,也就是__call__所执行的东西
# 1、先造一个空对象=>People  ,调用类中__new__方法
# 2、调用Mxmet这个类内的__ init__ 方法，完成初始化对象的操作
# 3、返回初始化好的对象
#============================================ 
